package com.xzzz.irda.guardcat.core.metric.thread;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import com.sun.management.ThreadMXBean;

import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.util.Date;
import java.util.Set;
import java.util.TreeSet;

/**
 * 线程信息
 *
 * @author xzzz
 * @since 1.0.0
 */
public class JvmThreadInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 当前活动线程的数量，包括守护线程和非守护线程。
     */
    private int threadCount;
    /**
     * 自 Java 虚拟机启动或峰值重置以来的峰值活动线程数。
     */
    private int peakThreadCount;
    /**
     * 自 Java 虚拟机启动以来创建和启动的线程总数。
     */
    private long totalStartedThreadCount;
    /**
     * 返回当前的实时守护线程数
     */
    private int daemonThreadCount;
    /**
     * 当前时间
     */
    private Date creTime;

    /**
     * 获取简单的线程信息；
     *
     * @return JvmThreadInfo Jvmx 线程信息
     */
    public static JvmThreadInfo getSimpleJvmThreadInfo() {
        JvmThreadInfo jvmThreadInfo = new JvmThreadInfo();

        ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
        jvmThreadInfo.threadCount = threadMxBean.getThreadCount();
        jvmThreadInfo.peakThreadCount = threadMxBean.getPeakThreadCount();
        jvmThreadInfo.totalStartedThreadCount = threadMxBean.getTotalStartedThreadCount();
        jvmThreadInfo.daemonThreadCount = threadMxBean.getDaemonThreadCount();
        jvmThreadInfo.creTime = DateUtil.date();
        return jvmThreadInfo;
    }

    /**
     * 通过线程ID 获取线程信息
     *
     * @param threadId 线程ID
     * @return ThreadMsg
     */
    public static ThreadMsg getThreadMsgByThreadId(Long threadId) {
        ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfoArr = threadMxBean.dumpAllThreads(true, true);
        if (ArrayUtil.isEmpty(threadInfoArr)) {
            return null;
        }

        for (ThreadInfo threadInfo : threadInfoArr) {
            if (null == threadInfo) {
                continue;
            }
            if (threadId.equals(threadInfo.getThreadId())) {
                threadId = threadInfo.getThreadId();
                return new ThreadMsg(threadInfo, threadMxBean.getThreadCpuTime(threadId), threadMxBean.getThreadUserTime(threadId));
            }
        }
        return null;
    }

    /**
     * 获取所有的线程信息
     *
     * @return Set<ThreadMsg>
     */
    public static Set<ThreadMsg> getAllThreadMsgSet() {
        Set<ThreadMsg> threadMsgList = new TreeSet<>();
        ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfoArr = threadMxBean.dumpAllThreads(true, true);
        if (ArrayUtil.isEmpty(threadInfoArr)) {
            return threadMsgList;
        }

        long threadId;
        ThreadMsg threadMsg;
        for (ThreadInfo threadInfo : threadInfoArr) {
            if (null == threadInfo) {
                continue;
            }
            threadId = threadInfo.getThreadId();
            threadMsg = new ThreadMsg(threadInfo, threadMxBean.getThreadCpuTime(threadId), threadMxBean.getThreadUserTime(threadId));
            threadMsgList.add(threadMsg);
        }

        return threadMsgList;
    }

    /**
     * 获取所有的死锁线程信息【包含 synchronized 死锁 和 通过 AbstractQueuedSynchronizer 实现的锁的死锁】
     *
     * @return Set<ThreadMsg>
     */
    public static Set<ThreadMsg> getDeadlockedThreadMsgSet() {
        ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
        return getThreadMsgSet(threadMxBean, threadMxBean.findDeadlockedThreads());
    }

    /**
     * 获取所有的 synchronized 死锁线程信息
     *
     * @return Set<ThreadMsg>
     */
    public static Set<ThreadMsg> getMonitorDeadlockedThreadMsgSet() {
        ThreadMXBean threadMxBean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
        return getThreadMsgSet(threadMxBean, threadMxBean.findMonitorDeadlockedThreads());
    }

    /**
     * 获取线程列表信息
     *
     * @return Set<ThreadMsg>
     */
    private static Set<ThreadMsg> getThreadMsgSet(ThreadMXBean threadMxBean, long[] threadIdArr) {
        Set<ThreadMsg> threadMsgList = new TreeSet<>();
        if (ArrayUtil.isEmpty(threadIdArr)) {
            return threadMsgList;
        }

        ThreadInfo[] threadInfoArr = threadMxBean.dumpAllThreads(true, true);
        if (ArrayUtil.isEmpty(threadInfoArr)) {
            return threadMsgList;
        }

        ThreadMsg threadMsg;
        for (Long threadId : threadIdArr) {
            for (ThreadInfo threadInfo : threadInfoArr) {
                if (null == threadInfo) {
                    continue;
                }
                if (threadId.equals(threadInfo.getThreadId())) {
                    threadId = threadInfo.getThreadId();
                    threadMsg = new ThreadMsg(threadInfo, threadMxBean.getThreadCpuTime(threadId), threadMxBean.getThreadUserTime(threadId));
                    threadMsgList.add(threadMsg);
                }
            }
        }
        return threadMsgList;
    }

    public int getThreadCount() {
        return threadCount;
    }

    public int getPeakThreadCount() {
        return peakThreadCount;
    }

    public long getTotalStartedThreadCount() {
        return totalStartedThreadCount;
    }

    public int getDaemonThreadCount() {
        return daemonThreadCount;
    }

    public Date getCreTime() {
        return creTime;
    }

    public static void main(String[] args) {
        System.out.println(getSimpleJvmThreadInfo().threadCount);
        System.out.println(getSimpleJvmThreadInfo().totalStartedThreadCount);
        System.out.println(getSimpleJvmThreadInfo().daemonThreadCount);
        System.out.println(getSimpleJvmThreadInfo().peakThreadCount);
    }
}
